/*
 * Copyright (c) 2021-2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.yuki312.backoff.example;

import com.yuki312.backoff.ktx.BackoffExt;
import com.yuki312.backoff.rxjava2.RxBackoff;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import ohos.app.Context;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import io.reactivex.rxjava3.openharmony.schedulers.OpenHarmonySchedulers;
import retrofit2.http.GET;
import retrofit2.http.Streaming;
import retrofit2.http.Url;

public class RetrofitSample {
    Context context;
    FileOutputStream outputStream;
    final static String TAG = "RetrofitSample";
    private String IMAGE_BASE_URL = "https://file-examples-com.github.io/uploads/2017/10/";
    public static String IMAGE_NAME = "file_example_JPG_2500kB.jpg";
    private String OUT_FILE_NAME = "rxbackoff.jpg";
    private int BYTES = 4096;

    public RetrofitSample(Context context) {
        this.context = context;
    }

    public interface Api {
        @Streaming
        @GET
        Observable<ResponseBody> downloadImage(@Url String url);
    }

    void initFileOut(Context context) {
        try {
            File path = new File(context.getExternalFilesDir(null) + File.separator + OUT_FILE_NAME);
            outputStream = new FileOutputStream(path);
        } catch (IOException e) {
            LogUtil.error(TAG, "error file create!");
            e.printStackTrace();
        }


    }

    private void writeResponseBodyToDisk(long length, InputStream stream) {
        InputStream inputStream = null;
        try {
            try {
                byte[] fileReader = new byte[BYTES];

                long fileSize = length;
                long fileSizeDownloaded = 0;

                inputStream = stream;

                while (true) {
                    int read = inputStream.read(fileReader);

                    if (read == -1) {
                        break;
                    }

                    outputStream.write(fileReader, 0, read);

                    fileSizeDownloaded += read;

                    LogUtil.debug(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
                }

                outputStream.flush();
            } catch (IOException e) {
                LogUtil.error(TAG, "error file write!");
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }

                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } catch (IOException e) {
            LogUtil.error(TAG, "Error FileIO");
            e.printStackTrace();
        }
    }

    public Observable<ResponseBody> downloadImage() {

        initFileOut(context);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(IMAGE_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .build();
        Api api = retrofit.create(Api.class);

        Observable<ResponseBody> observable = api.downloadImage(IMAGE_NAME);
        observable.subscribeOn(Schedulers.io())
                .observeOn(OpenHarmonySchedulers.mainThread())
                .retryWhen(RxBackoff.of(BackoffExt.binaryExponentialBackoff(), 5).observable())
                .subscribe(this::onImageResponse, this::onFailure);
        return observable;
    }

    private void onFailure(Throwable throwable) {
        LogUtil.error(TAG,"onFailure");
    }

    private void onImageResponse(ResponseBody response) {
        if (response != null) {
            writeResponseBodyToDisk(response.contentLength(), response.byteStream());
        } else {
            LogUtil.error(TAG,"response == null " + (response == null));
        }
    }
}
